package com.beiding.render;


import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.runtime.Undefined;

import javax.script.*;
import java.util.*;

//脚本执行单元
public class ScriptUtils {


    private static ScriptEngineManager manager = new ScriptEngineManager();
    private static ScriptEngine js = manager.getEngineByName("nashorn");

/*

    private static void handleArray(Map<String, Boolean> map, StringBuilder builder, Subsection next) {

        //c[1][2].d
        //c            y
        //c[1]         y
        //c[1][2]      n


        //
        for (int ind : next.inds) {

        }

    }
*/


    //创建一个执行引擎并执行相关的表达式,根据执行的返回值判断真假
    public static boolean exeBoolean(Map data, String expression) {

        Object exe = exe(data, expression);

        if (exe == null) {
            return false;
        }

        if (exe.equals("") || exe.equals(false)) {
            return false;
        }

        if (exe instanceof Number) {
            return ((Number) exe).doubleValue() != 0.0;
        }

        return true;
    }

    private static class HolderUnit {
        private boolean isScript;
        private String content;
    }

    /*

        java.{{className}}

     */

    private static class A {
        int index;
        int len;
        int type;
    }

    private static List<HolderUnit> splitHolders(String text) {
        List<A> as = new ArrayList<>();
        int p = 0;

        while (true) {
            p = text.indexOf("{{", p);
            if (p == -1) {
                break;
            }
            A a = new A();
            a.index = p;
            a.len = 2;
            a.type = 1;
            as.add(a);
            /*
                java.{{a}}.{{b}}
                       ^
                游标后移两位
             */

            p += 2;
        }

        p = 0;

        while (true) {
            p = text.indexOf("}}", p);
            if (p == -1) {
                break;
            }
            A a = new A();
            a.index = p;
            a.len = 2;
            a.type = 2;
            as.add(a);
            /*
                java.{{a}}.{{b}}
                       ^
                游标后移两位
             */

            p += 2;
        }

        //进行排序处理
        as.sort(Comparator.comparingInt(a -> a.index));

        List<HolderUnit> units = new ArrayList<>();

        if (as.size() == 0) {
            HolderUnit holderUnit = new HolderUnit();
            holderUnit.isScript = false;
            holderUnit.content = text;
            units.add(holderUnit);
        } else {
            //开始进行处理
            //开始进行逐个单元的处理
            /*
                a.{{A}}.b.{{b}}.c

                字符串-占位符
                字符串-占位符
                ...
                字符串
             */
            int stringStart = 0;
            int startPair = -1;
            for (A a : as) {
                if (a.type == 1) {
                    if (startPair != -1) {
                        throw new RuntimeException("不可匹配占位符符号:{{");
                    }
                    startPair = a.index;//放入占位符
                } else {
                    if (startPair == -1) {
                        throw new RuntimeException("不可匹配占位符符号:}}");
                    }

                    if (stringStart != startPair) {
                        String string = text.substring(stringStart, startPair);
                        HolderUnit holderUnit = new HolderUnit();
                        holderUnit.isScript = false;
                        holderUnit.content = string;
                        units.add(holderUnit);
                    }
                    String hold = text.substring(startPair + 2, a.index);
                    HolderUnit holderUnit = new HolderUnit();
                    holderUnit.isScript = true;
                    holderUnit.content = hold;
                    units.add(holderUnit);
                    startPair = -1;
                    stringStart = a.index + 2;
                }
            }
            if (stringStart < text.length()) {
                String string = text.substring(stringStart);
                HolderUnit holderUnit = new HolderUnit();
                holderUnit.isScript = false;
                holderUnit.content = string;
                units.add(holderUnit);
            }

        }

        return units;

    }


    //把执行的结果留在data中
    public static Object exe(Map data, String expression) {

        try {

            if (expression == null) {
                return null;
            }

            expression = expression.trim();

            if (expression.equals("")) {
                return null;
            }

            SimpleScriptContext simpleScriptContext = new SimpleScriptContext();
            simpleScriptContext.setBindings(new SimpleBindings(data), ScriptContext.ENGINE_SCOPE);
            String s = expression.replace("'", "\\'");//字符串符号转移

       //     System.out.println(s);

            s = ensureRight(s);

            String func = "function(){r=eval('" + s + "');return r;}";

        //    System.out.println(func);

            //TODO 将脚本转移一下
            ScriptObjectMirror jsObject = (ScriptObjectMirror) js.eval(func, simpleScriptContext);

            Object r = jsObject.call(data);
            //将结果带出来
            ScriptHelper.moveGlobal(data);
            if (r instanceof Undefined) {
                return null;
            }
            return r;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static Map exeGetData(String preDo) {
        Map map = new HashMap();
        exe(map, preDo);
        return (Map) map.get("nashorn.global");
    }


    public interface Executor {
        void exe(Map data);
    }


    public static void doFor(Map data, String expression, Executor executor) {
        SimpleScriptContext simpleScriptContext = new SimpleScriptContext();
        SimpleBindings bindings = new SimpleBindings() {
            @Override
            public boolean containsKey(Object key) {
                boolean b = super.containsKey(key);
                if (b) {
                    return true;
                }
                return data.containsKey(key);
            }

            @Override
            public Object get(Object key) {
                Object o = super.get(key);
                if (o != null) {
                    return o;
                }
                return data.get(key);
            }
        };
        simpleScriptContext.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
        try {
            bindings.put("_theExecutor", (Executor) ignore -> {
                Map gb = (Map) bindings.get("nashorn.global");//更高优先级

                try {
                    executor.exe(gb);
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
            js.eval(ensureRight("for(" + expression + ")_theExecutor.exe(null);"), simpleScriptContext);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }


    public static ScriptEngine createScriptEngine() {
        SimpleScriptContext simpleScriptContext = new SimpleScriptContext();
        simpleScriptContext.setBindings(new SimpleBindings(), ScriptContext.ENGINE_SCOPE);
        simpleScriptContext.setBindings(new SimpleBindings(), ScriptContext.GLOBAL_SCOPE);
        ScriptEngine js = manager.getEngineByName("nashorn");
        js.setContext(simpleScriptContext);
        return js;
    }


    public static Object parseHolder(Map data, String holder) {
        if (holder == null) {
            return null;
        }


        List<HolderUnit> units = splitHolders(holder);

        if (units.size() == 0) {
            return holder;
        }

        if (units.size() == 1) {
            HolderUnit holderUnit = units.get(0);
            if (holderUnit.isScript) {
                return exe(data, holderUnit.content);
            } else {
                return holderUnit.content;
            }
        }

        //一定是字符串
        StringBuilder builder = new StringBuilder();


        for (HolderUnit unit : units) {

            if (unit.isScript) {
                builder.append(exe(data, unit.content));
            } else {
                builder.append(unit.content);
            }
        }
        return builder.toString();
    }


    private static String ensureRight(String script) {//不能再对其中的换行脚本进行替换处理????
        return script.replace("\\r","\\\\r").replace("\\n", "\\\\n").replace("\r", "\\r").replace("\n", "\\n");
        //return script;
    }
/*

    public static void main(String[] args) throws ScriptException {

        //定义函数

        js.eval("var function_166345451464654646446464=function (data){data['name']='aaaa'+data['name'];return data}");

        System.out.println(js.eval("function_166345451464654646446464({name:'dingchanglei'})"));


    }
*/

}
